<template>
  <div
    ref="terminal"
    id="Terminal"
    class="xterm"
    style="height: 10%; width: 100%"
  ></div>
  <!-- <button @click="tt">close</button> -->
</template>
<script lang="ts" setup>
import WebSocketBean from "@/util/websocket/WebSocketBean";
import { IWebSocketBeanParam } from "@/util/websocket/websocket";
import { useTagsViewStore } from "@/store/modules/SshtagsView";
import {
  nextTick,
  onMounted,
  ref,
  reactive,
  onUnmounted,
  onBeforeMount,
  defineComponent,
  computed,
  watch,
  ComputedRef,
} from "vue";
import "xterm/css/xterm.css";
import "xterm/lib/xterm.js";
import {
  IBufferRange,
  IDecoration,
  IDecorationOptions,
  IDisposable,
  ILinkProvider,
  IMarker,
  ITerminalAddon,
  Terminal,
} from "xterm";
import { Message, SshSubMenu } from "@/entity/entitys";
// xterm.js的插件，使终端的尺寸适合包含元素。
import { FitAddon } from "xterm-addon-fit";
// xterm.js的附加组件，用于附加到Web Socket
import { AttachAddon } from "xterm-addon-attach";
const tagsViewStore = useTagsViewStore();
let wsTime: any = reactive<any>("");
//import System from '~/utils/System'
let term: Terminal = reactive<Terminal>(
  new Terminal({
    rows: 40, //行数，影响最小高度
    cols: 100, // 列数，影响最小宽度
    convertEol: true, //启用时，光标将设置为下一行的开头
    scrollback: 50, //终端中的滚动条回滚量
    disableStdin: false, //是否应禁用输入。
    cursorStyle: "underline", //光标样式
    cursorBlink: true, //光标闪烁
    theme: {
      foreground: "#F8F8F8",
      background: "#2D2E2C",
      cursor: "help", //设置光标
    },
    fontFamily: '"Cascadia Code", Menlo, monospace',
  })
);
let fitAddon: FitAddon = new FitAddon();
const terminal = ref();

// 用户输入
let command: String = reactive<String>("");
onMounted(() => {
  if ("WebSocket" in window) {
    nextTick(() => {
      userWrite();
    });
    start();
  } else {
    console.log("浏览器不支持 WebSocket..");
  }
});
//活跃的tag
const Title = computed(() => tagsViewStore.getTitle);
//使用侦听器监听 count 的变化
watch(Title, (newCount, oldCount) => {
  console.log(`Title changed from ${oldCount} to ${newCount}`);
});
const activeTag: ComputedRef<SshSubMenu> = computed(
  () => tagsViewStore.getActiveTag
);
watch(activeTag, (newCount, oldCount) => {
  console.log(`activeTag changed from ${oldCount.address} to ${newCount.address}`);
  if (oldCount.address != newCount.address) {
    term.clear();
  }
});
onUnmounted(() => {
  close();
});
enum MessageType {
  /**
   * 收到发来的消息
   */
  Get,
  /**
   * 发送到服务器的消息
   */
  Send,
  /**
   * 通知
   */
  Message,
}

const conf = reactive({
  status: "未连接",
  messagetype: {
    [MessageType.Get]: "收到",
    [MessageType.Send]: "发送",
    [MessageType.Message]: "通知",
  } as any,
  message: [] as {
    time: any;
    type: MessageType;
    data: any;
  }[],
  url: "ws://127.0.0.1:5555",
  send: "",
});

const addMessage = (type: MessageType, ctx: any) => {
  conf.message.push({
    time: new Date().toJSON(),
    type: type,
    data: ctx,
  });
};

const sendSuffix = "";

/**
 * 获取连接参数，也可以直接写入，这里是因为对地址进行了配置，所以每次连接都更新一次地址
 */
const getParam = () => {
  return {
    url: conf.url,
    needReconnect: true,
    reconnectGapTime: 3000,
    sendSuffix,
    messageSuffix: sendSuffix,
    heartSend: "JAVA",
    heartGet: "JAVA",
    heartGapTime: 10000,
    onopen: () => {
      addMessage(MessageType.Message, "连接成功");
    },
    onmessage: (data: any) => {
      //console.log("data.data: " + data.data.message_type)
      let message: Message = JSON.parse(data.data) as Message;
      if (message.message_type != "HEARTBEAT") {
        //sp.forEach((ctx: any) => {
        term.write("\r\n");
        writeOfColor(message.data, "0;", "37m");
        term.write("\r\n$ ");
        addMessage(MessageType.Get, message.data);
        //})
      } else {
        console.log("HEARTBEAT 心跳测试: " + message.data);
      }
    },
    onerror: () => {
      addMessage(MessageType.Message, "连接失败:" + conf.url);
    },
  } as IWebSocketBeanParam;
};
interface Info {
  Message_type: string;
  data: string;
}
/**
 * websocket示例，主要维护和使用对象
 */
const ws = new WebSocketBean(getParam());
const start = () => {
  // ws.start()
  ws.start(getParam());
  console.log("已建立连接：", event);
  // 输入换行符可让终端显示当前用户的工作路径
  // ws.send("\n");//这边原来是放开状态,但由于后台数据返回原因会报错,就直接注释了
  // 窗口自适应插件
  // 窗口尺寸变化时，终端尺寸自适应

  fitAddon.activate(term);
  //给新的这个ws服务使用依赖设置样式
  term.loadAddon(fitAddon);
  //给新的这个ws服务使用依赖初始化
  //term.loadAddon(attachAddon)
  term.open(terminal.value);
  // // 聚焦闪烁光标
  term.focus();
  ////先默认一次适应大小
  setTimeout(() => {
    fitAddon.fit();
  }, 1000);
  window.onresize = () => {
    fitAddon.fit();
  };
  writeDefaultInfo();
};

// 自定义终端默认展示内容
function writeDefaultInfo() {
  let defaultInfo = [
    "┌\x1b[1m terminals \x1b[0m─────────────────────────────────────────────────────────────────┐ ",
    "│                                                                            │ ",
    "│  \x1b[1;34m 欢迎使用Web Docker SSH \x1b[0m                                                  │ ",
    "│                                                                            │ ",
    "└────────────────────────────────────────────────────────────────────────────┘ ",
  ];
  // 测试颜色区间
  // let arr = Array.from({length:100},(v,i)=>v = i)
  // console.log(arr)
  // arr.map((item,i) => {
  //     defaultInfo.push(`Hello from \x1B[1;3;${i}m ${i} \x1B[0m  \u2764\ufe0f   ${i}`)
  // })
  term.write(defaultInfo.join("\n\r"));
  //writeOfColor("\n\r我是加粗斜体红色的字呀", "1;3;", "31m");
  term.write("\n\r$ ");
}
//
function writeOfColor(
  txt: string | ArrayBuffer | null,
  fontCss = "",
  bgColor = ""
) {
  // 在Linux脚本中以 \x1B[ 开始，中间前部分是样式+内容，以 \x1B[0m 结尾
  // 示例 \x1B[1;3;31m 内容 \x1B[0m
  // fontCss
  // 0;-4;字体样式（0;正常 1;加粗 2;变细 3;斜体 4;下划线）
  // bgColor
  // 30m-37m字体颜色（30m:黑色 31m:红色 32m:绿色 33m:棕色字 34m:蓝色 35m:洋红色/紫色 36m:蓝绿色/浅蓝色 37m:白色）
  // 40m-47m背景颜色（40m:黑色 41m:红色 42m:绿色 43m:棕色字 44m:蓝色 45m:洋红色/紫色 46m:蓝绿色/浅蓝色 47m:白色）
  term.write(`\x1B[${fontCss}${bgColor}${txt}\x1B[0m`);
}

// 监听输入
function userWrite() {
  term.onData((e) => {
    switch (e) {
      case "\u0003": // Ctrl+C
        term.write("^C ");
        term.write("\r\n$ ");
        break;
      case "\r": // Enter
        if (command == "clear") {
          term.clear();
          fitAddon.fit();
          command = "";
          term.write("\r\n$ ");
        } else if (command != "" && command != undefined) {
          ws.send(JSON.stringify({ message_type: "COMMAND", data: command })); //根据后台返回的数据,需要传入一个对象,里边key值为message,并对这个对象进行序列化
          // this.ws.send("\n");//这边原来是放开状态,但由于后台数据返回原因会报错,就直接注释了
          command = "";
        }

        break;
      case "\u007F": // Backspace (DEL)
        // Do not delete the prompt
        console.log("{}:", term);
        term.write("\b \b");
        if (command.length > 0) {
          command = command.substr(0, command.length - 1);
        }
        break;
      default: // Print all other characters for demo
        if (
          (e >= String.fromCharCode(0x20) && e <= String.fromCharCode(0x7e)) ||
          e >= "\u00a0"
        ) {
          command += e;
          writeOfColor(e, "2;3;", "33m");
          console.log("用户输入command", command);
        }
    }
  });
}
const close = () => {
  ws.dispose();
  addMessage(MessageType.Message, "关闭连接成功");
};

const sendMessage = () => {
  if (ws.status === 1) {
    const sendStatus = ws.send(conf.send);
    if (sendStatus) {
      addMessage(MessageType.Send, conf.send);
      console.log("发送成功");
    }
  } else {
    console.log("未连接");
  }
};
</script>
